package com.yingxue.lesson.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.yingxue.lesson.contants.Constant;
import com.yingxue.lesson.entity.SysPermission;
import com.yingxue.lesson.entity.SysRole;
import com.yingxue.lesson.exception.BusinessException;
import com.yingxue.lesson.exception.code.BaseResponseCode;
import com.yingxue.lesson.mapper.SysPermissionMapper;
import com.yingxue.lesson.mapper.SysRoleMapper;
import com.yingxue.lesson.mapper.SysRolePermissionMapper;
import com.yingxue.lesson.service.*;
import com.yingxue.lesson.utils.PageUtil;
import com.yingxue.lesson.utils.TokenSetting;
import com.yingxue.lesson.vo.req.AddRoleReqVO;
import com.yingxue.lesson.vo.req.RolePageReqVo;
import com.yingxue.lesson.vo.req.RolePermissionOperationReqVO;
import com.yingxue.lesson.vo.req.roleVo.RoleUpdateReqVO;
import com.yingxue.lesson.vo.resp.PageVO;
import com.yingxue.lesson.vo.resp.PermissionRespNodeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class RoleServiceImpl implements RoleService {

    @Autowired
    private SysRoleMapper roleMapper;
    @Autowired
    private RolePermissionService rolePermissionService;
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private TokenSetting tokenSetting;

    /**
     * 查询所有角色 --分页
     */
    @Override
    public PageVO<SysRole> pageInfo(RolePageReqVo vo) {
        PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
        List<SysRole> sysRoles =roleMapper.selectAll(vo);
        return PageUtil.getPageVo(sysRoles);
    }

    /**
     * 查询所有角色
     */
    @Override
    public List<SysRole> selectAll() {
        return roleMapper.selectAll(new RolePageReqVo());
    }

    /**
     * 添加角色
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysRole addRole(AddRoleReqVO vo) {
        //1.添加角色单表
        SysRole sysRole = new SysRole();
        BeanUtils.copyProperties(vo,sysRole);
        sysRole.setId(UUID.randomUUID().toString());
        sysRole.setCreateTime(new Date());
        int i = roleMapper.insertSelective(sysRole);
        if (i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //2.添加角色-权限中间表
        if(vo.getPermissions() !=null && !vo.getPermissions().isEmpty()){
            RolePermissionOperationReqVO reqVO = new RolePermissionOperationReqVO();
            reqVO.setRoleId(sysRole.getId());
            reqVO.setPermissionIds(vo.getPermissions());
            rolePermissionService.addRolePermission(reqVO);
        }
        return sysRole;
    }

    /**
     * 查询角色详情
     */
    @Override
    public SysRole detailInfo(String id) {
        //1.根绝角色id获取角色详情
        SysRole sysRole = roleMapper.selectByPrimaryKey(id);
        if (sysRole == null){
            log.error("传入 的 id:{}不合法",id);
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }

        //2.获取所有的菜单权限数据封装成树形结构
        List<PermissionRespNodeVO> permissionRespNodeVOS = permissionService.selectAllTree();

        //3.获取该角色关联的所有菜单权限id集合
        List<String> roleIds = rolePermissionService.getPermissionIdsByRoleId(id);
        HashSet<String> hashSet = new HashSet<>(roleIds);

        //4.遍历菜单权限树数据(最外层的叶子节点如果在菜单权限集合内就设置checked=true其它都是默认false)
        setChecked(permissionRespNodeVOS,hashSet);
        sysRole.setPermissionRespNodes(permissionRespNodeVOS);

        return sysRole;
    }

    //?????
    private void setChecked(List<PermissionRespNodeVO> list, Set<String> checkList){

        for(PermissionRespNodeVO node:list){
            /**
             * 子集选中从它往上到跟目录都被选中，父级选中从它到它所有的叶子节点都会被选中
             * 这样我们就直接遍历最底层及就可以了
             */
            if(checkList.contains(node.getId())&&(node.getChildren()==null||node.getChildren().isEmpty())){
                node.setChecked(true);
            }
            setChecked((List<PermissionRespNodeVO>) node.getChildren(),checkList);

        }
    }

    /**
     * 更新角色
     */
    @Override
    public void updateRole(RoleUpdateReqVO vo) {
        //1.把角色信息保存
        SysRole sysRole = roleMapper.selectByPrimaryKey(vo.getId());
        if (sysRole == null){
            log.error("传入 的 id:{}不合法",vo.getId());
            throw new BusinessException(BaseResponseCode.DATA_ERROR);
        }
        BeanUtils.copyProperties(vo,sysRole);
        sysRole.setUpdateTime(new Date());
        int i = roleMapper.updateByPrimaryKeySelective(sysRole);
        if (i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }

        //2.把角色和菜单权限关联数据修改
        RolePermissionOperationReqVO reqVO = new RolePermissionOperationReqVO();
        reqVO.setRoleId(vo.getId());
        reqVO.setPermissionIds(vo.getPermissions());
        rolePermissionService.addRolePermission(reqVO);

        //3.把该角色关联的用户标记起来，需要去刷新jwt token
        List<String> userIds = userRoleService.getRoleIdsByUserId(vo.getId());
        for (String userId : userIds) {
            //标记用户 在用户认证的时候判断这个是否主动刷过
            redisService.set(Constant.JWT_REFRESH_KEY+userId,userId,tokenSetting.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);
            //清楚用户授权数据缓存
            redisService.delete(Constant.IDENTIFY_CACHE_KEY);
        }
    }


    /**
     * 删除角色
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRole(String roleId) {
        //1.角色数据逻辑删除
        SysRole sysRole = new SysRole();
        sysRole.setId(roleId);
        sysRole.setUpdateTime(new Date());
        sysRole.setDeleted(0);
        int i = roleMapper.updateByPrimaryKeySelective(sysRole);
        if (i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }
        //2.角色菜单权限关联数据删除
        rolePermissionService.removeByRoleId(roleId);

        List<String> userIds = userRoleService.getUserIdsByRoleId(roleId);
        //3.角色用户关联数据删除
        userRoleService.removeByRoleId(roleId);
        //4.把跟该角色关联的用户标记起来，需要刷新token

        if (!userIds.isEmpty()){
            for (String userId : userIds) {
                //标记用户 在用户认证的时候判断这个是否主动刷过
                redisService.set(Constant.JWT_REFRESH_KEY+userId,userId,tokenSetting.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);
                //清楚用户授权数据缓存
                redisService.delete(Constant.IDENTIFY_CACHE_KEY+userId);
            }
        }


    }


    /**
     * 根据用户id 查询 角色名字
     */
    @Override
    public List<String> getRoleNameByUserId(String userId) {
        //1.通过中间表 通过userId 查询 roleIds
        List<String> roleIds = userRoleService.getRoleIdsByUserId(userId);
        if(roleIds.isEmpty()){
            return null;
        }
        //2.通过 roleIds 查询 角色名字
        List<String> roleName = roleMapper.getRoleNameByRoleIds(roleIds);
        return roleName;
    }
}
